//
// Created by Ivor_ on 2024/1/30.
//

#include "linkedList.h"

LIST_NODE* createNodeLLN(const void* _data, size_t dataSize, LIST_NODE* _next) {
    LIST_NODE* newNode = (LIST_NODE*)malloc(sizeof(LIST_NODE));
    newNode->data = malloc(dataSize + 1);
    memset(newNode->data, 0, dataSize + 1);
    memcpy(newNode->data, _data, dataSize), newNode->next = _next;
    return newNode;
}

LINKED_LIST * createListLLN() {
    LINKED_LIST* newList = (LINKED_LIST*)malloc(sizeof(LINKED_LIST));
    newList->len = 0, newList->dummyHead = createNodeLLN(NULL, 0, NULL);
    return newList;
}

void freeNodeLLN(LIST_NODE* nodeObj) {
    free(nodeObj->data);
    free(nodeObj);
}

void freeListLLN(LINKED_LIST* listObj) {
    while (listObj->dummyHead) {
        LIST_NODE* _next = listObj->dummyHead->next;
        freeNodeLLN(listObj->dummyHead);
        listObj->dummyHead = _next;
    }
    free(listObj);
}

void insertNodeLLN(LINKED_LIST* listObj, int index, const void* _data, size_t dataSize) {
    LIST_NODE* newNode = createNodeLLN(_data, dataSize, NULL);
    (listObj->len) ++;
    if (index <= 0) {
        LIST_NODE* temp = listObj->dummyHead->next;
        listObj->dummyHead->next = newNode;
        newNode->next = temp;
        return;
    }
    LIST_NODE* traveller = listObj->dummyHead;
    while (traveller->next && index) {
        traveller = traveller->next, index--;
    }
    LIST_NODE* temp = traveller->next;
    traveller->next = newNode;
    newNode->next = temp;
}

void insertToNextNodeLLN(LINKED_LIST* listObj, LIST_NODE* nodeObj, const void* _data, size_t dataSize) {
    LIST_NODE* newNode = createNodeLLN(_data, dataSize, nodeObj->next);
    nodeObj->next = newNode;
    (listObj->len) ++;
}

void removeNodeLLN(LINKED_LIST* listObj, int index) {
    if (!listObj->dummyHead->next) {
        fprintf(stderr, "Cannot remove node from a empty list, did you mean `freeListLLN`?\n");
        return;
    }
    (listObj->len) --;
    if (index <= 0) {
        LIST_NODE* temp = listObj->dummyHead->next;
        listObj->dummyHead->next = temp->next;
        freeNodeLLN(temp);
        return;
    }
    LIST_NODE* traveller = listObj->dummyHead;
    while (traveller->next && traveller->next->next && index) {
        traveller = traveller->next, index--;
    }
    LIST_NODE* temp = traveller->next;
    traveller->next = temp->next;
    freeNodeLLN(temp);
}

void removeNextNodeLLN(LINKED_LIST* listObj, LIST_NODE* nodeObj) {
    if (!nodeObj->next) {
        fprintf(stderr, "Cannot remove node from list tail, did you mean `removeNodeLLN(<index> = <infinity>)`?\n");
        return;
    }
    LIST_NODE* temp = nodeObj->next;
    nodeObj->next = temp->next;
    freeNodeLLN(temp);
    (listObj->len) --;
}

LIST_NODE* findNodeLLN(const LINKED_LIST* listObj, const void* _data, size_t dataSize) {
    LIST_NODE* traveller = listObj->dummyHead->next;
    while (traveller) {
        if (!memcmp(traveller->data, _data, dataSize)) {
            return traveller;
        }
        traveller = traveller->next;
    }
    return NULL;
}

LIST_NODE* getNodeLLN(const LINKED_LIST* listObj, int index) {
    LIST_NODE* traveller = listObj->dummyHead->next;
    for (int i = 0; i < index && traveller && traveller->next; ++i) {
        traveller = traveller->next;
    }
    return traveller;
}

void updateNodeLLN(LINKED_LIST* listObj, int index, const void* _data, size_t dataSize) {
    LIST_NODE* obj = getNodeLLN(listObj, index);
    if (!obj) {
        fprintf(stderr, "Cannot update a NULL node, did you mean `createNodeLLN`?\n");
        return;
    }
    realloc(obj->data, dataSize + 1);
    memset(obj->data, 0, dataSize + 1);
    memcpy(obj->data, _data, dataSize);
}

void updateThisNodeLLN(LIST_NODE* nodeObj, const void* _data, size_t dataSize) {
    if (!nodeObj) {
        fprintf(stderr, "Cannot update a NULL node, did you mean `createNodeLLN`?\n");
        return;
    }
    realloc(nodeObj->data, dataSize);
    memset(nodeObj->data, 0, dataSize + 1);
    memcpy(nodeObj->data, _data, dataSize);
}

void printListLLN(const LINKED_LIST* listObj, const char* format, FILE* io) {
    LIST_NODE* traveller = listObj->dummyHead->next;
    while (traveller) {
        fprintf(io, format, *(long long int*)(traveller->data));
        traveller = traveller->next;
    }
}
